/*
* Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

pub trait Encoder {
    type Error;

    fn advance(&mut self, n: usize);

    fn check_capacity(&self, capacity: usize, needed: usize) -> Result<(), Self::Error>;
    fn ensure_capacity(&mut self, buf: &mut Vec<u8>, needed: usize) -> Result<(), Self::Error>;

    fn put_bool(&mut self, buf: &mut Vec<u8>, val: bool) -> Result<(), Self::Error>;
    fn put_u8(&mut self, buf: &mut Vec<u8>, val: u8) -> Result<(), Self::Error>;
    fn put_u16(&mut self, buf: &mut Vec<u8>, val: u16) -> Result<(), Self::Error>;
    fn put_u32(&mut self, buf: &mut Vec<u8>, val: u32) -> Result<(), Self::Error>;
    fn put_u64(&mut self, buf: &mut Vec<u8>, val: u64) -> Result<(), Self::Error>;
    fn put_i8(&mut self, buf: &mut Vec<u8>, val: i8) -> Result<(), Self::Error>;
    fn put_i16(&mut self, buf: &mut Vec<u8>, val: i16) -> Result<(), Self::Error>;
    fn put_i32(&mut self, buf: &mut Vec<u8>, val: i32) -> Result<(), Self::Error>;
    fn put_i64(&mut self, buf: &mut Vec<u8>, val: i64) -> Result<(), Self::Error>;
    fn put_f32(&mut self, buf: &mut Vec<u8>, val: f32) -> Result<(), Self::Error>;
    fn put_f64(&mut self, buf: &mut Vec<u8>, val: f64) -> Result<(), Self::Error>;
    fn put_bytes(&mut self, buf: &mut Vec<u8>, bytes: &[u8]) -> Result<(), Self::Error>;
    fn put_str(&mut self, buf: &mut Vec<u8>, s: &str) -> Result<(), Self::Error>;

    unsafe fn put_bool_unchecked(&mut self, buf: &mut [u8], val: bool);
    unsafe fn put_u8_unchecked(&mut self, buf: &mut [u8], val: u8);
    unsafe fn put_u16_unchecked(&mut self, buf: &mut [u8], val: u16);
    unsafe fn put_u32_unchecked(&mut self, buf: &mut [u8], val: u32);
    unsafe fn put_u64_unchecked(&mut self, buf: &mut [u8], val: u64);
    unsafe fn put_i8_unchecked(&mut self, buf: &mut [u8], val: i8);
    unsafe fn put_i16_unchecked(&mut self, buf: &mut [u8], val: i16);
    unsafe fn put_i32_unchecked(&mut self, buf: &mut [u8], val: i32);
    unsafe fn put_i64_unchecked(&mut self, buf: &mut [u8], val: i64);
    unsafe fn put_f32_unchecked(&mut self, buf: &mut [u8], val: f32);
    unsafe fn put_f64_unchecked(&mut self, buf: &mut [u8], val: f64);
    unsafe fn put_bytes_unchecked(&mut self, buf: &mut [u8], bytes: &[u8]);
    unsafe fn put_str_unchecked(&mut self, buf: &mut [u8], s: &str);
}

#[derive(Default)]
pub struct DefaultEncoder {
    offset: usize,
}

#[derive(Debug, thiserror::Error)]
pub enum DefaultEncoderError {
    #[error("Not enough space in buffer")]
    NotEnoughSpace,
}

impl Encoder for DefaultEncoder {
    type Error = DefaultEncoderError;

    fn advance(&mut self, n: usize) {
        self.offset += n;
    }

    fn check_capacity(&self, capacity: usize, needed: usize) -> Result<(), Self::Error> {
        if self.offset + needed > capacity {
            Err(DefaultEncoderError::NotEnoughSpace)
        } else {
            Ok(())
        }
    }

    fn ensure_capacity(&mut self, buf: &mut Vec<u8>, needed: usize) -> Result<(), Self::Error> {
        if self.offset + needed > buf.len() {
            // allocate more space
            let additional = std::cmp::max(buf.len() * 2, self.offset + needed) - buf.len();
            buf.reserve(additional);
            // resize exactly to the needed size
            buf.resize(buf.len() + needed, 0);
        }
        Ok(())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// DefaultEncoder::new().put_bool(&mut buf, true);
    /// assert_eq!(buf, vec![1]);
    /// ```
    fn put_bool(&mut self, buf: &mut Vec<u8>, val: bool) -> Result<(), Self::Error> {
        self.put_u8(buf, val as u8)
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// DefaultEncoder::new().put_u8(&mut buf, 123);
    /// assert_eq!(buf, vec![123]);
    /// ```
    fn put_u8(&mut self, buf: &mut Vec<u8>, val: u8) -> Result<(), Self::Error> {
        self.put_bytes(buf, &val.to_le_bytes())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// DefaultEncoder::new().put_u16(&mut buf, 0x1234);
    /// assert_eq!(buf, vec![0x34, 0x12]);
    /// ```
    fn put_u16(&mut self, buf: &mut Vec<u8>, val: u16) -> Result<(), Self::Error> {
        self.put_bytes(buf, &val.to_le_bytes())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// DefaultEncoder::new().put_u32(&mut buf, 0x12345678);
    /// assert_eq!(buf, vec![0x78, 0x56, 0x34, 0x12]);
    /// ```
    fn put_u32(&mut self, buf: &mut Vec<u8>, val: u32) -> Result<(), Self::Error> {
        self.put_bytes(buf, &val.to_le_bytes())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// DefaultEncoder::new().put_u64(&mut buf, 0x1122334455667788);
    /// assert_eq!(buf, vec![0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]);
    /// ```
    fn put_u64(&mut self, buf: &mut Vec<u8>, val: u64) -> Result<(), Self::Error> {
        self.put_bytes(buf, &val.to_le_bytes())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// DefaultEncoder::new().put_i8(&mut buf, -42);
    /// assert_eq!(buf, vec![0xD6]);
    /// buf.clear();
    /// DefaultEncoder::new().put_i8(&mut buf, 123);
    /// assert_eq!(buf, vec![123]);
    /// ```
    fn put_i8(&mut self, buf: &mut Vec<u8>, val: i8) -> Result<(), Self::Error> {
        self.put_bytes(buf, &val.to_le_bytes())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// DefaultEncoder::new().put_i16(&mut buf, -42);
    /// assert_eq!(buf, vec![0xD6, 0xFF]);
    /// buf.clear();
    /// DefaultEncoder::new().put_i16(&mut buf, 0x1234);
    /// assert_eq!(buf, vec![0x34, 0x12]);
    /// ```
    fn put_i16(&mut self, buf: &mut Vec<u8>, val: i16) -> Result<(), Self::Error> {
        self.put_bytes(buf, &val.to_le_bytes())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// let val: i32 = -12345678i32;
    /// DefaultEncoder::new().put_i32(&mut buf, val);
    /// assert_eq!(buf, vec![0xB2, 0x9E, 0x43, 0xFF]);
    /// ```
    fn put_i32(&mut self, buf: &mut Vec<u8>, val: i32) -> Result<(), Self::Error> {
        self.put_bytes(buf, &val.to_le_bytes())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// let val: i64 = 0xFF439EB2;
    /// DefaultEncoder::new().put_i64(&mut buf, val);
    /// assert_eq!(buf, vec![0xB2, 0x9E, 0x43, 0xFF, 0x00, 0x00, 0x00, 0x00]);
    /// ```
    fn put_i64(&mut self, buf: &mut Vec<u8>, val: i64) -> Result<(), Self::Error> {
        self.put_bytes(buf, &val.to_le_bytes())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// let val: f32 = 1.0;
    /// DefaultEncoder::new().put_f32(&mut buf, val);
    /// assert_eq!(buf, vec![0x00, 0x00, 0x80, 0x3F]);
    /// ```
    fn put_f32(&mut self, buf: &mut Vec<u8>, val: f32) -> Result<(), Self::Error> {
        self.put_bytes(buf, &val.to_le_bytes())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// let val: f64 = 1.0;
    /// DefaultEncoder::new().put_f64(&mut buf, val);
    /// assert_eq!(buf, vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F]);
    /// ```
    fn put_f64(&mut self, buf: &mut Vec<u8>, val: f64) -> Result<(), Self::Error> {
        self.put_bytes(buf, &val.to_le_bytes())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// let arr: [u8; 5] = [10, 20, 30, 40, 50];
    /// let val: &[u8] = &arr[..];
    /// DefaultEncoder::new().put_bytes(&mut buf, val);
    /// assert_eq!(buf, vec![10, 20, 30, 40, 50]);
    /// ```
    fn put_bytes(&mut self, buf: &mut Vec<u8>, bytes: &[u8]) -> Result<(), Self::Error> {
        self.ensure_capacity(buf, bytes.len())?;
        unsafe { self.put_bytes_unchecked(buf, bytes) };
        Ok(())
    }

    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = Vec::new();
    /// let val: &str = "Hello, world!";
    /// DefaultEncoder::new().put_str(&mut buf, val);
    /// assert_eq!(buf, vec![72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]);
    /// ```
    fn put_str(&mut self, buf: &mut Vec<u8>, s: &str) -> Result<(), Self::Error> {
        self.put_bytes(buf, s.as_bytes())
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 1];
    /// unsafe { DefaultEncoder::new().put_bool_unchecked(&mut buf, true) };
    /// assert_eq!(buf, vec![1]);
    /// ```
    unsafe fn put_bool_unchecked(&mut self, buf: &mut [u8], val: bool) {
        unsafe { self.put_u8_unchecked(buf, val as u8) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 1];
    /// unsafe { DefaultEncoder::new().put_u8_unchecked(&mut buf, 123) };
    /// assert_eq!(buf, vec![123]);
    /// ```
    unsafe fn put_u8_unchecked(&mut self, buf: &mut [u8], val: u8) {
        unsafe { self.put_bytes_unchecked(buf, &val.to_le_bytes()) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 2];
    /// unsafe { DefaultEncoder::new().put_u16_unchecked(&mut buf, 0x1234) };
    /// assert_eq!(buf, vec![0x34, 0x12]);
    /// ```
    unsafe fn put_u16_unchecked(&mut self, buf: &mut [u8], val: u16) {
        unsafe { self.put_bytes_unchecked(buf, &val.to_le_bytes()) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 4];
    /// unsafe { DefaultEncoder::new().put_u32_unchecked(&mut buf, 0x12345678) };
    /// assert_eq!(buf, vec![0x78, 0x56, 0x34, 0x12]);
    /// ```
    unsafe fn put_u32_unchecked(&mut self, buf: &mut [u8], val: u32) {
        unsafe { self.put_bytes_unchecked(buf, &val.to_le_bytes()) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 8];
    /// unsafe { DefaultEncoder::new().put_u64_unchecked(&mut buf, 0x1122334455667788) };
    /// assert_eq!(buf, vec![0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]);
    /// ```
    unsafe fn put_u64_unchecked(&mut self, buf: &mut [u8], val: u64) {
        unsafe { self.put_bytes_unchecked(buf, &val.to_le_bytes()) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 1];
    /// unsafe { DefaultEncoder::new().put_i8_unchecked(&mut buf, -42) };
    /// assert_eq!(buf, vec![0xD6]);
    /// ```
    unsafe fn put_i8_unchecked(&mut self, buf: &mut [u8], val: i8) {
        unsafe { self.put_bytes_unchecked(buf, &val.to_le_bytes()) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 2];
    /// unsafe { DefaultEncoder::new().put_i16_unchecked(&mut buf, -42) };
    /// assert_eq!(buf, vec![0xD6, 0xFF]);
    /// ```
    unsafe fn put_i16_unchecked(&mut self, buf: &mut [u8], val: i16) {
        unsafe { self.put_bytes_unchecked(buf, &val.to_le_bytes()) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 4];
    /// unsafe { DefaultEncoder::new().put_i32_unchecked(&mut buf, -12345678i32) };
    /// assert_eq!(buf, vec![0xB2, 0x9E, 0x43, 0xFF]);
    /// ```
    unsafe fn put_i32_unchecked(&mut self, buf: &mut [u8], val: i32) {
        unsafe { self.put_bytes_unchecked(buf, &val.to_le_bytes()) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 8];
    /// unsafe { DefaultEncoder::new().put_i64_unchecked(&mut buf, 0xFF439EB2) };
    /// assert_eq!(buf, vec![0xB2, 0x9E, 0x43, 0xFF, 0x00, 0x00, 0x00, 0x00]);
    /// ```
    unsafe fn put_i64_unchecked(&mut self, buf: &mut [u8], val: i64) {
        unsafe { self.put_bytes_unchecked(buf, &val.to_le_bytes()) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 4];
    /// let val: f32 = 1.0;
    /// unsafe { DefaultEncoder::new().put_f32_unchecked(&mut buf, val) };
    /// assert_eq!(buf, vec![0x00, 0x00, 0x80, 0x3F]);
    /// ```
    unsafe fn put_f32_unchecked(&mut self, buf: &mut [u8], val: f32) {
        unsafe { self.put_bytes_unchecked(buf, &val.to_le_bytes()) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 8];
    /// let val: f64 = 1.0;
    /// unsafe { DefaultEncoder::new().put_f64_unchecked(&mut buf, val) };
    /// assert_eq!(buf, vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F]);
    /// ```
    unsafe fn put_f64_unchecked(&mut self, buf: &mut [u8], val: f64) {
        unsafe { self.put_bytes_unchecked(buf, &val.to_le_bytes()) }
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 5];
    /// let arr: [u8; 5] = [10, 20, 30, 40, 50];
    /// let val: &[u8] = &arr[..];
    /// unsafe { DefaultEncoder::new().put_bytes_unchecked(&mut buf, val) };
    /// assert_eq!(buf, vec![10, 20, 30, 40, 50]);
    /// ```
    unsafe fn put_bytes_unchecked(&mut self, buf: &mut [u8], bytes: &[u8]) {
        buf[self.offset..self.offset + bytes.len()].copy_from_slice(bytes);
        self.offset += bytes.len();
    }

    /// # Safety
    /// 
    /// This method is unsafe because it allows the caller to provide a buffer with insufficient capacity.
    /// 
    /// # Examples
    /// 
    /// ```
    /// use ohmw_core::bincode::{Encoder, DefaultEncoder};
    /// 
    /// let mut buf = vec![0; 13];
    /// let val: &str = "Hello, world!";
    /// unsafe { DefaultEncoder::new().put_str_unchecked(&mut buf, val) };
    /// assert_eq!(buf, vec![72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]);
    /// ```
    unsafe fn put_str_unchecked(&mut self, buf: &mut [u8], s: &str) {
        unsafe { self.put_bytes_unchecked(buf, s.as_bytes()) }    
    }
}

impl DefaultEncoder {
    pub fn new() -> Self {
        Self { offset: 0 }
    }
}
